import { Status } from "https://deno.land/x/oak/mod.ts";
BigInt.prototype.toJSON = function () { return `${this}` };
import { renderHtml } from "./render.js";
import { search } from "./search.js";
// https://node-postgres.com/features/connecting
import { Application, Router } from "https://deno.land/x/oak/mod.ts";
import { Client } from "https://deno.land/x/postgres@v0.17.0/mod.ts";
// const DATABASE_URL="postgresql://nopains:kSfmEDYacg4bxM3bHIdVzQ@saucy-ibis-3340.6xw.cockroachlabs.cloud:26257/fancuiruo?sslmode=verify-full"
const dictionary = ['abc']
const app = new Application();
const port = 8080;
const router = new Router();
const client = new Client(DATABASE_URL);
const disableRegister = false

// Instead of using a global client, create new connections for each request
async function getDbClient() {
  const client = new Client(DATABASE_URL);
  await client.connect();
  return client;
}
function getRandomInt8() {
  // 生成从 -128 到 127 的随机整数
  return Math.floor(Math.random() * 256) - 128;
}
// 执行注册
async function register(userId, auth, ctx) {
  // let personId = +new Date()
  // @ts-ignore
  if (disableRegister === true) {
    let result = await checkAuth(ctx)
    if (!result) {
      return {
        data: null,
        error: 'register is disabled'
      }
    } else {
      if (result.uid !== 'xiangyun') {
        return {
          data: null,
          error: 'only admin can register currently'
        }
      }
    }
  }
  let exist = await getAuth(userId)
  // 已经存在用户
  if (exist) {
    return {
      data: null,
      error: 'duplicate userId'
    }
  }
  const client = await getDbClient();
  let queryString = `INSERT INTO public.users VALUES('${parseInt(getRandomInt8())}', '', '${userId}', '', '${auth}')`
  // 创建用户
  let result = {}
  try {
    result = await client.queryArray(queryString);
  } catch (e) {
    return {
      data: null,
      error: e.message
    }
  } finally {
    await client.end();
  }
  return {
    userId,
    auth
  }
}

// 获取auth信息
async function getAuth(userId) {
  let queryString = `SELECT * FROM public.users where firstname = '${userId}'`
  console.log(queryString)
  const client = await getDbClient();
  let result = {}
  try {
    result = await client.queryArray(queryString);
  } catch (error) {
    console.log(error)
  } finally {
    await client.end();
  }
  console.log(result)
  // if find a user then 
  if (result.rows.length > 0) {
    let auth = result.rows[0][4]
    console.log('auth', auth)
    return auth
  } else {
    return false
  }
}

// 检查auth
async function checkAuth(ctx) {
  // 如果存在x-auth和x-uid 而且auth正确则返回true
  let authHeader = ctx.request.headers.get("x-auth")
  let userId = ctx.request.headers.get("x-uid")
  // 不存在认证信息
  if(!authHeader || !userId) {
    return {}
  }
  let result = await getAuth(userId)
  console.log(authHeader, userId, result)
  if (authHeader === result) {
    return {
      uid: userId,
      auth: authHeader
    }
  } else {
    ctx.response.status = Status.Forbidden;
    return null
  }
}

// 登陆
router.post("/api/login", async (ctx) => {
  // 获取搜索关键词
  let result = await checkAuth(ctx)
  ctx.response.body = { result: result };
  ctx.response.type = "json";
  ctx.response.status = Status.OK;
});

// 注册
router.post("/api/register", async (ctx) => {
  // // 获取搜索关键词
  // const body = await (((typeof ctx.request.body === 'function') ? ctx.request.body : ctx.request.body.json)()); // content type automatically detected
  // let requestBody = body;
  // if (body.type === "json") {
  //   requestBody = await body.value; // an object of parsed JSON
  // }
  const requestBody = await parseRequestBody(ctx);
  console.log('requestBody:', requestBody)
  let value = requestBody
  if (requestBody.type === "json") {
    value = await requestBody.value; // an object of parsed JSON
  }
  console.log(value)
  let result = await register(value.uid, value.auth, ctx)
  ctx.response.body = { result: result };
  ctx.response.type = "json";
  ctx.response.status = Status.OK;
});
// 创建用户表格
// 创建测试表格
let createUsersTable = async () => {
  await client.connect();
  try {
    // const results = await client.query("SELECT NOW()");
    const result = await client.queryArray(`
      CREATE TABLE Users
        (
        PersonID int,
        LastName varchar(255),
        FirstName varchar(255),
        Address varchar(255),
        Auth varchar(255)
        )`);
    // console.log(results.rows);
    return result
  } catch (err) {
    console.error("error executing query:", err);
  } finally {
    // client.end();
  }
};

// 创建图书表格
// 创建测试表格
let createPersonsTable = async () => {
  await client.connect();
  try {
    // const results = await client.query("SELECT NOW()");
    const result = await client.queryArray(`CREATE TABLE Persons
        (
        PersonID int,
        LastName varchar(255),
        FirstName varchar(255),
        Address varchar(255),
        City varchar(255)
        )`);
    // console.log(results.rows);
    return result
  } catch (err) {
    console.error("error executing query:", err);
  } finally {
    // client.end();
  }
};

// 获取结果
// 初始化所有结果
let getResult = async (keyword?:string) => {
  const client = await getDbClient();
  await client.connect();
  try {
    let results = {
      rows: [],
    }
    if (!keyword) {
      results = await client.queryArray("SELECT *  from public.persons");
    } else {
      results = await client.queryArray(`SELECT *  from public.persons WHERE firstname LIKE '%${keyword}%';`);
    }
    return results
  } catch (err) {
    console.error("error executing query:", err);
  } finally {
    await client.end(); // Always close the connection
  }
};

// 渲染html
router.get("/", async (ctx) => {
  let result = await getResult()
  const authResult = await checkAuth(ctx)
  const uid = authResult?.uid
  console.log('uid:', uid)
  ctx.response.body = renderHtml("", result?.rows || [], uid);
});

// 搜索
router.get("/api/search", async (ctx) => {
  // 获取搜索关键词
  const authResult = await checkAuth(ctx)
  const uid = authResult?.uid
  const pattern = ctx.request.url.searchParams.get("search-text");
  ctx.response.body = renderHtml(pattern, search(pattern, dictionary),  uid);
});

// router.get("/api/search-new", async (ctx) => {
//   const client = await getDbClient();
//   const pattern = ctx.request.url.searchParams.get("search-text");
//   ctx.response.body = { hello: pattern };
//   ctx.response.type = "json";
//   ctx.response.status = Status.OK;
// })

// 获取信息
router.get("/api/reasons", async (ctx) => {
  const pattern = ctx.request.url.searchParams.get("search-text");
  let result = await getResult(pattern)
  // let result = await createTable()
  ctx.response.body = { result: result };
  console.log(result?.rows)
  ctx.response.type = "json";
  ctx.response.status = Status.OK;
})

// 兼容不同版本的body解析函数
async function parseRequestBody(ctx: any): Promise<any> {
  try {
    // Try the newer Oak version approach first
    if (typeof ctx.request.body === 'function') {
      const body = await ctx.request.body();
      if (body.type === "json") {
        return await body.value;
      }
      return body;
    }
    // Try the older approach
    else if (typeof ctx.request.body.json === 'function') {
      return await ctx.request.body.json();
    }
    // Try calling body directly if it's a function
    else if (typeof ctx.request.body === 'function') {
      const body = await ctx.request.body();
      if (body && body.type === "json" && body.value) {
        return await body.value;
      }
      return body;
    }
    // Fallback - try to call body as a method
    else {
      const bodyMethod = ctx.request.body;
      if (typeof bodyMethod === 'function') {
        const body = await bodyMethod();
        if (body && body.type === "json" && body.value) {
          return await body.value;
        }
        return body;
      }
    }
  } catch (error) {
    console.error("Error parsing request body:", error);
    throw new Error("Unable to parse request body");
  }
  
  // If all else fails, return empty object
  return {};
}

// 提交表格
router.post("/api/reasons", async (ctx) => {
  const authResult = await checkAuth(ctx)
  console.log(authResult)
  // console.log(ctx.request.body())
  // const doFetch = typeof ctx.request.body === 'function' ? ctx.request.body : ctx.request.body.json;
  // console.log(typeof ctx.request.body)
  // console.log(doFetch)
  // // const result = await ctx.request.body(); // content type automatically detected
  // const result = await (doFetch()); // content type automatically detected
  // console.log(result)
  // let value = result
  // if (result.type === "json") {
  //   value = await result.value; // an object of parsed JSON
  // }
  const value = await parseRequestBody(ctx);
    // const authResult = await checkAuth(ctx);
  let wechat = value.wechat || ''
  let bookName = value.bookName || ''
  // let personId = +new Date()
  console.log(value)
  // Generate PersonID that includes user information
  let timestamp = Date.now();
  let userId = authResult?.uid;
  // Simple way to include user info in ID (take first 3 chars of username)
  let userPrefix = userId.substring(0, 3).charCodeAt(0).toString().substring(0, 3);
  // Make sure this is a number that fits in the int field
  let personId = parseInt(timestamp.toString().slice(0, 10) + userPrefix); 
  console.log(personId)
  // @todo
  let queryString = `INSERT INTO public.persons (PersonID, LastName, FirstName, Address, City) VALUES('${personId}','${wechat}','${bookName}','test','test');`
  console.log(queryString)
  const client = await getDbClient();
  let insertResult = {}
  try {
    insertResult = await client.queryArray(queryString);
  } catch (e) {
    console.error(e)
  } finally {
    await client.end()
  }
  ctx.response.body = { result: insertResult };
  ctx.response.type = "json";
  ctx.response.status = Status.OK;
})

// 删除
router.delete("/api/reasons/:id", async (ctx) => {
  let authResult = await checkAuth(ctx)
  if (!authResult) {
    return; // checkAuth already set the response
  }
  const client = await getDbClient();
    try {
    let id = ctx.params.id;
    
    // Check if user is admin (can delete anything)
    if (authResult?.uid === 'xiangyun') {
      // Admin can delete any entry
      let queryString = `DELETE FROM public.persons WHERE PersonID=${id}`
      console.log(queryString)
      let deleteResult = await client.queryArray(queryString);
      
      ctx.response.body = { result: deleteResult };
      ctx.response.type = "json";
      ctx.response.status = Status.OK;
      return;
    }
    
    // For regular users, check if they own this entry
    // Extract user info from PersonID (last 3 digits are user prefix)
    let userPrefix = authResult.uid.substring(0, 3).charCodeAt(0).toString().substring(0, 3);
    
    // Check if this entry belongs to the user
    if (id.toString().endsWith(userPrefix)) {
      let queryString = `DELETE FROM public.persons WHERE PersonID=${id}`
      console.log(queryString)
      let deleteResult = await client.queryArray(queryString);
      
      ctx.response.body = { result: deleteResult };
      ctx.response.type = "json";
      ctx.response.status = Status.OK;
    } else {
      ctx.response.status = Status.Forbidden;
      ctx.response.body = { message: "您没有权限删除此条目" };
    }
  } catch (e) {
    console.error(e);
    ctx.response.status = Status.InternalServerError;
    ctx.response.body = { message: "删除失败" };
  } finally {
    await client.end();
  }
  // if (!result) {
  //   await client.end();
  // } else {
  //   if (result.uid !== 'xiangyun') {
  //     ctx.response.status = Status.Forbidden;
  //     ctx.response.body = { message: "管理员才有权限删除" };
  //     return
  //   }
  //   let id = ctx.params.id
  //   let queryString = `DELETE FROM public.persons where PersonID=${id}`
  //   console.log(queryString)
  //   let insertResult = {}
  //   try {
  //     insertResult = await client.queryArray(queryString);

  //   } catch (e) {
  //     console.error(e)
  //   } finally {
  //     await client.end()
  //   }
  //   ctx.response.body = { result: insertResult };
  //   ctx.response.type = "json";
  //   ctx.response.status = Status.OK;
  // }
})

// for await (const conn of server) {
//  // In order to not be blocking, we need to handle each connection individually
//  // without awaiting the function
//  serveHttp(conn);
// }

// async function serveHttp(conn: Deno.Conn) {
async function serveHttp() {
  // TODO
  // This "upgrades" a network connection into an HTTP connection.
  //  const httpConn = Deno.serveHttp(conn);
  // Each request sent over the HTTP connection will be yielded as an async
  // iterator from the HTTP connection.
  let jsonStringifyResults = ''
  let results = []
  //  for await (const requestEvent of httpConn) {
  // The native HTTP server uses the web standard `Request` and `Response`
  // objects.
  try {
    // results = await client.queryArray("SELECT *  from public.persons");
    // jsonStringifyResults = results.rows.length
    // results = await getResult()
    //  results = await createUsersTable()
    results = await createPersonsTable()
  } catch (e) {
    console.error(e)
  } finally {
  }
  // const body = `Your user-agent is:\n\n${
  // requestEvent.request.headers.get("user-agent") + jsonStringifyResults ?? "Unknown"
  // }`;
  let body = {
    // result: results.rows.length
    result: results?.rows || []
  }
  body = JSON.stringify(body)
  // console.log(body)
  // The requestEvent's `.respondWith()` method is how we send the response
  // back to the client.
  // 返回接口
  // requestEvent.respondWith(
  console.log(new Response(body, {
    headers: {
      "Access-Control-Allow-Origin": "*",
      "content-type": "application/json; charset=utf-8",
      // "content-type": "text/plain; charset=utf-8",
    },
    status: 200,
  }))
  // );
  //  }
}
// serveHttp()
// Add this CORS middleware before defining routes
app.use(async (ctx, next) => {
  ctx.response.headers.set("Access-Control-Allow-Origin", "*");
  ctx.response.headers.set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS");
  ctx.response.headers.set("Access-Control-Allow-Headers", "Content-Type, x-auth, x-uid");
  
  if (ctx.request.method === "OPTIONS") {
    ctx.response.status = Status.OK;
    return;
  }

  await next();
});
app.use(router.routes());
app.use(router.allowedMethods());

await app.listen({ port });
console.log("Listening at http://localhost:" + port);
